package com.yang.system.domain.orgMng.emp;

import com.yang.system.common.framework.domain.AggregateRoot;
import com.yang.system.domain.common.exception.BusinessException;
import lombok.Builder;
import lombok.Data;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

import static com.yang.system.domain.orgMng.emp.EmpStatus.PROBATION;
import static com.yang.system.domain.orgMng.emp.EmpStatus.REGULAR;

@Data
@Builder
public class Emp extends AggregateRoot {
    // 只读
    private Long id;
    private Long tenantId;
    // 读写

    private Long org;

    private String num;

    private String idNum;

    private String name;

    private String gender;

    private Date dob;

    private EmpStatus empStatus;

    private List<Skill> skills;              // 读写
    private List<WorkExperience> experiences;// 读写
    private List<String> postCodes;          // 读写，岗位代码

    public Emp(Long tenantId, Long id, LocalDateTime createdAt, Long createdBy) {
        super(createdAt, createdBy);
        this.tenantId = tenantId;
    }

    public Optional<Skill> getSkill(Long skillTypeId) {
        return skills.stream()
                .filter(s -> Objects.equals(s.getSkillTypeId(), skillTypeId))
                .findAny();
    }

    public List<Skill> getSkills() {
        //把员工对象内部的技能列表转换成一个只读列表后再返回。外界只能读，不能增删，从而对技能实现了完全的封装。
        return Collections.unmodifiableList(skills);
    }

    /**
     * 用 addSkill() 方法来增加技能。外界不是直接创建技能对象，而是把创建技能对象的“素材”作为参数传递给 addSkill() 方法，从而在聚合根内部创建技能对象。
     * @param skillTypeId
     * @param level
     * @param duration
     * @param userId
     */
    public void addSkill(Long skillTypeId, SkillLevel level, int duration, Long userId) {
        // 调用业务规则: 同一技能不能录入两次
        skillTypeShouldNotDuplicated(skillTypeId);
        Skill newSkill = new Skill(tenantId, skillTypeId, LocalDateTime.now(), userId);
        newSkill.setLevel(level);
        newSkill.setDuration(duration);
        skills.add(newSkill);
    }

    public Emp updateSkill(Long skillTypeId, SkillLevel level
            , int duration, Long userId) {
        Skill theSkill = this.getSkill(skillTypeId)
                .orElseThrow(() ->
                        new BusinessException("不存在要修改的skillTypeId!"));

        if (theSkill.getLevel() != level || theSkill.getDuration() != duration) {
            theSkill.setLevel(level);
            theSkill.setDuration(duration);
            theSkill.setLastUpdatedBy(userId);
            theSkill.setLastUpdatedAt(LocalDateTime.now());
            theSkill.toUpdate(); //设置修改状态
        }
        return this;
    }

    public Emp deleteSkill(Long skillTypeId) {
        this.getSkill(skillTypeId)
                .orElseThrow(() -> new BusinessException(
                        "不存在要删除的skillTypeId!"))
                .toDelete(); //设置修改状态
        return this;
    }

    public void addExperience(LocalDate startDate, LocalDate endDate, String company, Long userId) {
        // 调用业务规则: 工作经验的时间段不能重叠
        durationShouldNotOverlap(startDate, endDate);

        WorkExperience newExperience = new WorkExperience(
                tenantId,
                startDate,
                endDate,
                LocalDateTime.now(),
                userId);
        newExperience.setCompany(company);

        experiences.add(newExperience);
    }

    public Emp updateExperience(LocalDate startDate, LocalDate endDate, String company, Long userId) {
        // 与Skill的处理类似...
    }

    public Emp deleteExperience(LocalDate startDate, LocalDate endDate) {
        // 与Skill的处理类似...
    }

    public Emp addEmpPost(String postCode, Long userId) {
        // 与Skill的处理类似...
    }

    public Emp deleteEmpPost(String postCode, Long useId) {
        // 与Skill的处理类似...
    }

    private void skillTypeShouldNotDuplicated(Long newSkillTypeId) {
        if (skills.stream().anyMatch(s -> Objects.equals(s.getSkillTypeId(), newSkillTypeId))) {
            throw new BusinessException("同一技能不能录入两次！");
        }
    }



    private void durationShouldNotOverlap(LocalDate startDate, LocalDate endDate) {
        if (experiences.stream().anyMatch(e -> overlap(e, startDate, endDate))) {
            throw new BusinessException("工作经验的时间段不能重叠!");
        }
    }

    private boolean overlap(WorkExperience experience
            , LocalDate otherStart, LocalDate otherEnd) {
        LocalDate thisStart = experience.getStartDate();
        LocalDate thisEnd = experience.getEndDate();

        return otherStart.isBefore(thisEnd)
                && otherEnd.isAfter(thisStart);
    }

    //转正
    void becomeRegular() {
        // 调用业务规则: 试用期的员工才能被转正
        onlyProbationCanBecomeRegular();
        empStatus = REGULAR;
    }

    //终止
    void terminate() {
        // 调用业务规则: 已经终止的员工不能再次终止
        shouldNotTerminateAgain();
        empStatus = EmpStatus.TERMINATED;
    }

    // 实现业务规则
    private void onlyProbationCanBecomeRegular() {
        if (empStatus != PROBATION) {
            throw new BusinessException("试用期员工才能转正！");
        }
    }
    private void shouldNotTerminateAgain() {
        if (empStatus ==EmpStatus.TERMINATED ) {
            throw new BusinessException("已经终止的员工不能再次终止！");
        }
    }



}
